#include <iostream>
#include <mutex>
#include <vector>
#include <condition_variable>
#include <thread>

using namespace std;

class Object
{
public:
    Object(int ID):_ID(ID) {}
    void consume(void)
    {
        cout << "消费ID： " << this->_ID << "消费了" << endl;
    }
    int getId(void)
    {
        return this->_ID;
    }
private:
    int _ID;

};

class ConsumerAndProductor
{
public:
    void put(Object* obj)
    {
        unique_lock<mutex> lock(this->_mtx);
        while(!this->_cache_list.empty())
        {
            // 如果缓存队列中不为空则通知消费者进行消费
            /*
                条件变量wait会让当前线程进入等待状态，并释放互斥锁，以便让消费者线程能够去消费缓存队列中的数据
            */
            _cv.wait(lock);
        }
        this->_cache_list.push_back(obj);
        cout << "当前生产者生产编号: " << obj->getId() << endl;
        this->_cv.notify_all();
    }
    void get(void)
    {
        unique_lock<mutex> lock(this->_mtx);
        while(this->_cache_list.empty())
        {
            // 如果缓存队列为空就等待态并释放互斥锁以便让生产者线程能够存入数据
            this->_cv.wait(lock);
        }
        Object* tmp = this->_cache_list.back();
        tmp->consume();
        this->_cache_list.pop_back();
        this->_cv.notify_all();
        delete tmp;
    }
private:
    vector<Object*> _cache_list; // 缓存队列，生产者和消费者的共享资源
    mutex _mtx; // 互斥锁，保证同一时间内只有一个线程可以访问临界资源
    condition_variable _cv;
};

ConsumerAndProductor cap;

void ProductThreadFunc(void)
{
    unsigned int ID = 0;
    while(true)
    {
        Object* obj = new Object(++ ID);
        cap.put(obj);
        // 延时500ms生产
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
}

void ConsumeThreadFunc(void)
{
    while(true)
    {
        cap.get();
        // 延时500ms消费
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
}

int main(int argc, char const *argv[])
{
    vector<thread> productList;
    vector<thread> consumeList;
    // 创建三个生产者线程，三个消费者线程
    for(int i = 0; i < 3; i ++)
    {
        productList.push_back(thread(ProductThreadFunc));
        consumeList.push_back(thread(ConsumeThreadFunc));
    }
    for(int i = 0; i < 3; i ++)
    {
        productList[i].join();
        consumeList[i].join();
    }
    return 0;
}
